/** ###################################################################
**     Filename  : test.c
**     Project   : test
**     Processor : MC9S12XDT512BCFU
**     Version   : Driver 01.14
**     Compiler  : CodeWarrior HCS12X C Compiler
**     Date/Time : 8.11.2011, 6:14
**     Abstract  :
**         Main module.
**         This module contains user's application code.
**     Settings  :
**     Contents  :
**         No public methods
**
** ###################################################################*/
/* MODULE test */

/* Including needed modules to compile this module/procedure */
#include "Cpu.h"
#include "Events.h"
#include "TI1.h"
#include "AS1.h"
#include "AS2.h"
#include "GPIO1.h"
/* Include shared modules, which are used for whole project */
#include "PE_Types.h"
#include "PE_Error.h"
#include "PE_Const.h"
#include "IO_Map.h"

/* User includes (#include below this line is not maintained by Processor Expert) */
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>

// definice pro CAN
#define CANE 0x80
#define INITAK 1
#define INITRQ 1
#define SLPRQ 2
#define SLPAK 2

// definice LED
#define LED0 PORTA_PA7
#define LED1 PORTA_PA6
#define LED2 PORTA_PA5

// struktura pro CAN paket
typedef struct 
{
 word id;           // CAN identifikator
 byte len;          // delka dat
 byte data[8];      // data
} can_message_t;

// funkce pro CAN 0
byte can0_recv( can_message_t *pmess);
byte can0_send( can_message_t *pmess);
void can0_init( void);
// funkce pro CAN 1
byte can1_recv( can_message_t *pmess);
byte can1_send( can_message_t *pmess);
void can1_init( void);

// priznak interaptu od timeru
byte timer_int = 0;

// flag jestli uz je modul identifikovany a pripojeny k centralni jednotce
bool isConnected = 0;
// nahodne cislo z duvodu identifikace, vybere se pozdeji v kodu
byte randNumber = 0;
// standardni Node ID pro studenstke moduly
byte nodeID = 100;
// testovaci float cisla (po otestovani desky muzou byt smazana)
float xData1 = 3.5;
float xData2 = 11.1;

void main(void)
{
  /* Write your local variable definition here */
  byte ret;
  byte c;
  can_message_t can_msg;
  int state = 0;
  int divider = 0;

  /*** Processor Expert internal initialization. DON'T REMOVE THIS CODE!!! ***/
  PE_low_level_init();
  /*** End of Processor Expert internal initialization.                    ***/
  
  can0_init();
  can1_init();
  
  // generovani nahodneho cisla.
  // UPRAVIT pro zahrnuti nejakeho analogoveho vstupu pri generovani
  randNumber = (byte)( rand() % 255 );
  
  LED0 = 1;
  LED1 = 1;
  LED2 = 1;

  /* Write your code here */
  for( ;;)
  {
    // timer interrupt flag pouzity pro blikani LED diod (po otestovani desky nechat blikat pouze LED 0)
    if( timer_int == 1)
    {
      timer_int = 0;
      divider ++;
      if (divider > 10)
      {
        divider = 0;
        switch(state)
        {
          case 0:
          {
            LED0 = 0;
            LED1 = 1;
            LED2 = 1;
            state = 1;
            break;
          }
          case 1:
          {
            LED0 = 1;
            LED1 = 0;
            LED2 = 1;
            state = 2;
            break;
          }
          case 2:
          {
            LED0 = 1;
            LED1 = 1;
            LED2 = 0;
            state = 0;
            break;
          }
        }
      }
    }
    
    // echo na serial line 1 (po otestovani muze byt smazano)
    ret = AS1_RecvChar( &c);

    if( ret == ERR_OK)
    {
      LED0 = ~LED0;
      ( void) AS1_SendChar( c); while( AS1_GetTxComplete() == 0){};
    }    
    
    if( ret == ERR_OK)
    {
      LED0 = ~LED0;
      ( void) AS1_SendChar( c); while( AS1_GetTxComplete() == 0){};
    } 
    
    // echo na serial line 2 (po otestovani muze byt smazano)
    ret = AS2_RecvChar( &c);

    if( ret == ERR_OK)
    {
      LED0 = ~LED0;
      ( void) AS2_SendChar( c); while( AS2_GetTxComplete() == 0){};
    } 
    
    // po prijeti triggeru na CAN 1 odesle float cislo (po otestovani muze byt smazano)
    ret = can1_recv( &can_msg);
    if( ret == 1)
    {  
      can_msg.id = 315;                                 // CAN ID podle posilane veliciny, ted nastaveno na indikovanou vyducnou rychlost
      can_msg.len = 8;
      can_msg.data[0] = nodeID;                         // pridelene Node ID
      can_msg.data[1] = 2;                              // datovy typ float
      can_msg.data[2] = 0;                              // servisni kod
      can_msg.data[3] = 1;                              // cislo zpravy (relativni pozice v modulu - dalsi velicina by mela 2, atd...)
      can_msg.data[4] = ((byte *) & xData2)[0];          // Posilana data
      can_msg.data[5] = ((byte *) & xData2)[1];          // Posilana data
      can_msg.data[6] = ((byte *) & xData2)[2];          // Posilana data
      can_msg.data[7] = ((byte *) & xData2)[3];          // Posilana data
      while( !can1_send( &can_msg));
    }
    
    // identifikace modulu a posilani dat po CAN 0
    ret = can0_recv( &can_msg);
    if( ret == 1)
    {  
      switch(can_msg.id)
      {
        case 1:                                               // Triggerovani pro vycitani dat
        {
          if(isConnected)
          {
            LED1 = ~LED1;
            
            //
            // ZMERENI DAT pouze na trigger!
            //
            
            // simulace merene veliciny (po otestovani muze byt smazano)
            xData1 += 0.001;
            
            // odeslani zemrenych dat
            can_msg.id = 315;                                // CAN ID podle posilane veliciny, ted nastaveno na indikovanou vyducnou rychlost
            can_msg.len = 8;
            can_msg.data[0] = nodeID;                         // pridelene Node ID
            can_msg.data[1] = 2;                              // datovy typ float
            can_msg.data[2] = 0;                              // servisni kod
            can_msg.data[3] = 1;                              // cislo zpravy (relativni pozice v modulu - dalsi velicina by mela 2, atd...)
            can_msg.data[4] = ((byte *) & xData1)[0];          // Posilana data
            can_msg.data[5] = ((byte *) & xData1)[1];          // Posilana data
            can_msg.data[6] = ((byte *) & xData1)[2];          // Posilana data
            can_msg.data[7] = ((byte *) & xData1)[3];          // Posilana data
            while( !can0_send( &can_msg));
          }
        }break;
        
        case 3:                                               // Zadost o prideleni Node ID
        {
          if(!isConnected)
          {
            LED1 = ~LED1;
          
            can_msg.id = 5;                                   // identifikator pro zadost o Node ID
            can_msg.len = 8;
            can_msg.data[0] = 100;                            // Standardni nove Node ID
            can_msg.data[1] = 100;                            // Typ dat podle CANaerospace (user defined)
            can_msg.data[2] = 0;                              // Servisni kod podle CANaerospace
            can_msg.data[3] = 0;                              // cislo zpravy
            can_msg.data[4] = 1;                              // Pocet implementovanych kanalu v modulu
            can_msg.data[5] = randNumber;                     // Nahodne cislo z duvodu identifikace
            can_msg.data[6] = 0;                              // Pro dalsi vyuziti
            can_msg.data[7] = 0;                              // Pro dalsi vyuziti
            while( !can0_send( &can_msg));
          }
        }break;
        
        case 4:                                               // Ulozeni Node ID
        {
          if(!isConnected)
          {
            LED1 = ~LED1;
            
            if(can_msg.data[4] == randNumber)
            {
              nodeID = can_msg.data[5];
              isConnected = TRUE;
            }
          }
        }break;
      }
    }
  }

  /*** Processor Expert end of main routine. DON'T MODIFY THIS CODE!!! ***/
  for(;;){}
  /*** Processor Expert end of main routine. DON'T WRITE CODE BELOW!!! ***/
} /*** End of main routine. DO NOT MODIFY THIS TEXT!!! ***/

byte can0_recv( can_message_t *pmess)
{
 byte i, tmp;
  
 if( CAN0RFLG & 0x01) 
 {
   pmess->id = CAN0RXIDR0 << 8;
   pmess->id += CAN0RXIDR1;
   if( pmess->id & 0x0010) 
   { 
     pmess->len = 0x80;
   }
   else
   {
     pmess->len = 0;
   }
  
   pmess->id = ( pmess->id >> 5) & 0x07ff;
                                                                                                    
   if( ( CAN0RXDLR & 0x0f) > 8) 
   {
     pmess->len |= 0x08;
     tmp = 8;
   }
   else	
   {
     tmp = CAN0RXDLR & 0x0f;
     pmess->len |= tmp;  
   }
   
   for( i=0; i < tmp; i++)
   {
     pmess->data[i] = (&CAN0RXDSR0)[i];
   }
   CAN0RFLG = 0x01;
   return 1;
  }
  return 0;
}

byte can0_send( can_message_t *pmess)
{
  char i;
  unsigned short volatile *pireg;
 
  if( CAN0TFLG & 0x01)
  {
    pireg = ( unsigned short volatile *)( &CAN0TXIDR0);
    if( pmess->len & 0x80)
    { 
      *pireg = ( ( pmess->id << 5) & 0xffe0) | 0x0010;	// write id, rtr frame
    }
    else
    {
      *pireg = ( ( pmess->id << 5) & 0xffe0); // write id, data frame
    }
    pireg++;
    *pireg = 0;
    
    pmess->len &= 0x0f;
    for( i = 0; i < pmess->len; i++)
    {
      ( &CAN0TXDSR0)[i] = pmess->data[i];	  // write data
    }
    CAN0TXDLR = pmess->len; 	        // write dlc
    CAN0TFLG = 1;	 					  // start transmission
    return 1;
  }

  return 0;
}

void can0_init(void)
{
  CAN0CTL0 |= INITRQ; // set initrq, this will also set initak
  while( !( CAN0CTL1 & INITAK)); // wait for init mode to occur

  CAN0CTL1 = CANE; // set cane just in case this is the first time after reset

  CAN0BTR0=0x03; // for 500kbps 0x03, for 100kbps 0x13
  CAN0BTR1=0x32; // for a can Baud of 500kbps at 16Mhz crystal

  // can id filter bits
  CAN0IDAR0=0x00;
  CAN0IDAR1=0x00;
  CAN0IDAR2=0x00;
  CAN0IDAR3=0x00;
  CAN0IDAR4=0x00;
  CAN0IDAR5=0x00;
  CAN0IDAR6=0x00;
  CAN0IDAR7=0x00;

  // can id filter mask
  CAN0IDMR0=0xff;
  CAN0IDMR1=0xff;
  CAN0IDMR2=0xff;
  CAN0IDMR3=0xff;
  CAN0IDMR4=0xff;
  CAN0IDMR5=0xff;
  CAN0IDMR6=0xff;
  CAN0IDMR7=0xff;

  CAN0IDAC = 0x10; // set filters to 2 16 bit acceptance filters

  CAN0CTL0 &= ~INITRQ; // clear initrq
  while (CAN0CTL1 & INITAK);

  CAN0CTL1 |= CANE; // set cane just in case this is the first time after reset
  CAN0RIER_RXFIE = 0; // enable receive interrupt

  CAN0TBSEL = 1;
}

byte can1_recv( can_message_t *pmess)
{
 byte i, tmp;
  
 if( CAN4RFLG & 0x01) 
 {
   pmess->id = CAN4RXIDR0 << 8;
   pmess->id += CAN4RXIDR1;
   if( pmess->id & 0x0010) 
   { 
     pmess->len = 0x80;
   }
   else
   {
     pmess->len = 0;
   }
  
   pmess->id = ( pmess->id >> 5) & 0x07ff;
                                                                                                    
   if( ( CAN4RXDLR & 0x0f) > 8) 
   {
     pmess->len |= 0x08;
     tmp = 8;
   }
   else	
   {
     tmp = CAN4RXDLR & 0x0f;
     pmess->len |= tmp;  
   }
   
   for( i=0; i < tmp; i++)
   {
     pmess->data[i] = (&CAN4RXDSR0)[i];
   }
   CAN4RFLG = 0x01;
   return 1;
  }
  return 0;
}

byte can1_send( can_message_t *pmess)
{
  char i;
  unsigned short volatile *pireg;
 
  if( CAN4TFLG & 0x01)
  {
    pireg = ( unsigned short volatile *)( &CAN4TXIDR0);
    if( pmess->len & 0x80)
    { 
      *pireg = ( ( pmess->id << 5) & 0xffe0) | 0x0010;	// write id, rtr frame
    }
    else
    {
      *pireg = ( ( pmess->id << 5) & 0xffe0); // write id, data frame
    }
    pireg++;
    *pireg = 0;
    
    pmess->len &= 0x0f;
    for( i = 0; i < pmess->len; i++)
    {
      ( &CAN4TXDSR0)[i] = pmess->data[i];	  // write data
    }
    CAN4TXDLR = pmess->len; 	        // write dlc
    CAN4TFLG = 1;	 					  // start transmission
    return 1;
  }

  return 0;
}

void can1_init(void)
{
  CAN4CTL0 |= INITRQ; // set initrq, this will also set initak
  while( !( CAN4CTL1 & INITAK)); // wait for init mode to occur

  CAN4CTL1 = CANE; // set cane just in case this is the first time after reset

  CAN4BTR0=0x03; // for 500kbps 0x03, for 100kbps 0x13
  CAN4BTR1=0x32; // for a can Baud of 500kbps at 16Mhz crystal

  // can id filter bits
  CAN4IDAR0=0x00;
  CAN4IDAR1=0x00;
  CAN4IDAR2=0x00;
  CAN4IDAR3=0x00;
  CAN4IDAR4=0x00;
  CAN4IDAR5=0x00;
  CAN4IDAR6=0x00;
  CAN4IDAR7=0x00;

  // can id filter mask
  CAN4IDMR0=0xff;
  CAN4IDMR1=0xff;
  CAN4IDMR2=0xff;
  CAN4IDMR3=0xff;
  CAN4IDMR4=0xff;
  CAN4IDMR5=0xff;
  CAN4IDMR6=0xff;
  CAN4IDMR7=0xff;

  CAN4IDAC = 0x10; // set filters to 2 16 bit acceptance filters

  CAN4CTL0 &= ~INITRQ; // clear initrq
  while (CAN4CTL1 & INITAK);

  CAN4CTL1 |= CANE; // set cane just in case this is the first time after reset
  CAN4RIER_RXFIE = 0; // enable receive interrupt

  CAN4TBSEL = 0x7;
}

/* END test */
/*
** ###################################################################
**
**     This file was created by Processor Expert 3.02 [04.44]
**     for the Freescale HCS12X series of microcontrollers.
**
** ###################################################################
*/
